//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this sample source code is subject to the terms of the Microsoft
// license agreement under which you licensed this sample source code. If
// you did not accept the terms of the license agreement, you are not
// authorized to use this sample source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the LICENSE.RTF on your install media or the root of your tools installation.
// THE SAMPLE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES OR INDEMNITIES.
//
//
// (C) Copyright 2006 Marvell International Ltd.
// All Rights Reserved
//
//------------------------------------------------------------------------------
//
//  File:  device.c
//
#include <windows.h>
#include <oal.h>


//------------------------------------------------------------------------------
//
//  Function:  OALKitlFindDevice
//
//  This function find KITL device at specified location in devices table.
//  Depending on bus type it read device address and interrupt pin and translate
//  it to system address space and then to kernel virtual address.
//
OAL_KITL_DEVICE* OALKitlFindDevice(
    DEVICE_LOCATION *pDevLoc, OAL_KITL_DEVICE *pDevice
) {
    BOOL rc = FALSE;
    UINT32 space;
    UINT64 address;
    
    OALMSG(OAL_KITL&&OAL_FUNC, (
        L"+OALKitlFindDevice(%d/%d/%08x, 0x%08x)\r\n",
        pDevLoc->IfcType, pDevLoc->BusNumber, pDevLoc->LogicalLoc, pDevice
    ));

    // Look for driver in list
    while (pDevice->name != NULL && !rc) {

        // Is it our device? Then move
        if (pDevLoc->IfcType != pDevice->ifcType) {
            // Move to next driver
            pDevice++;
            continue;
        }            

        // Identify device and read its address/interrupt depends on bus type
        switch (pDevLoc->IfcType) {
        case InterfaceTypeUndefined:
            if (pDevLoc->LogicalLoc != pDevice->id) break;
            address = pDevLoc->LogicalLoc;
            rc = TRUE;
            break;
        case Internal:
            if (pDevLoc->LogicalLoc != pDevice->id) break;
            address = pDevLoc->LogicalLoc;
            rc = TRUE;
            break;
#ifdef KITL_PCI            
        case PCIBus:
            {
                UINT32 id;
                id = OALPCIGetId(
                    pDevLoc->BusNumber, *(OAL_PCI_LOCATION*)&pDevLoc->LogicalLoc
                );
                if (id != pDevice->id) break;
                address = OALPCIGetMBAR(
                    pDevLoc->BusNumber, 
                    *(OAL_PCI_LOCATION*)&pDevLoc->LogicalLoc, pDevice->resource
                );
                pDevLoc->Pin = OALPCIGetInterruptPin(
                    pDevLoc->BusNumber, *(OAL_PCI_LOCATION*)&pDevLoc->LogicalLoc
                );                
                rc = TRUE;
            }                
            break;
#endif
        }

        // If we don't identify device skip it
        if (!rc) {
            pDevice++;
            continue;
        }

        // When interface type is undefined physical address
        // is equal to logical, so break loop
        if (pDevLoc->IfcType == InterfaceTypeUndefined) {
            pDevLoc->PhysicalLoc = (VOID*)address;
            break;
        }

        // Translate bus address, if it fails skip device
        space = (UINT32)address & 0x1;
        address &= ~0x1;
        if (!OALIoTransBusAddress(
            pDevLoc->IfcType, pDevLoc->BusNumber, address, &space, &address
        )) {
            rc = FALSE;
            pDevice++;
            continue;
        }

        // If address has address above 32bit address space skip device
        if ((address >> 32) != 0) {
            rc = FALSE;
            pDevice++;
            continue;
        }

        // Do mapping to virtual address for memory space
        if (space == 0) {
            pDevLoc->PhysicalLoc = OALPAtoVA((UINT32)address, FALSE);
        }

        // We get all we need
        break;
    }

    // Return NULL if driver wasn't find
    if (!rc) pDevice = NULL;

    OALMSG(OAL_KITL&&OAL_FUNC, (
        L"-OALKitlFindDevice(pDevice = 0x%08x(%s), PhysicalLoc = 0x%08x)\r\n",
        pDevice, (pDevice != NULL) ? pDevice->name : L"", pDevLoc->PhysicalLoc
    ));
    return pDevice;
}


//------------------------------------------------------------------------------
//
//  Function:  OALKitlDeviceName
//
LPCWSTR OALKitlDeviceName(
    DEVICE_LOCATION *pDevLoc, OAL_KITL_DEVICE *pDevice
) {
    BOOL rc = FALSE;
    static WCHAR name[64];
    LPCWSTR pName = NULL;
    
    OALMSG(OAL_KITL&&OAL_FUNC, (
        L"+OALKitlDeviceName(%d/%d/%08x, 0x%08x)\r\n",
        pDevLoc->IfcType, pDevLoc->BusNumber, pDevLoc->LogicalLoc, pDevice
    ));

    // Look for driver in list
    while (pDevice->name != NULL && !rc) {

        // Is it our device? Then move
        if (pDevLoc->IfcType != pDevice->ifcType) {
            // Move to next driver
            pDevice++;
            continue;
        }            

        // Identify device and read its address/interrupt depends on bus type
        switch (pDevLoc->IfcType) {
        case Internal:
            if (pDevLoc->LogicalLoc != pDevice->id) break;
            pName = pDevice->name;
            rc = TRUE;
            break;
#ifdef KITL_PCI            
        case PCIBus:
            {
                UINT32 id;
                OAL_PCI_LOCATION pciLoc;

                pciLoc = *(OAL_PCI_LOCATION*)&pDevLoc->LogicalLoc;
                id = OALPCIGetId(pDevLoc->BusNumber, pciLoc);
                if (id != pDevice->id) break;
                OALLogPrintf(
                    name, sizeof(name)/sizeof(WCHAR), 
                    L"%s @ id %d bus %d dev %d fnc %d", 
                    pDevice->name, pDevLoc->BusNumber, pciLoc.bus, pciLoc.dev,
                    pciLoc.fnc
                );
                pName = name;
                rc = TRUE;
            }                
            break;
#endif
        }

        // If we don't identify device skip it
        if (!rc) {
            pDevice++;
            continue;
        }
            
        // We get all we need
        break;
    }


    OALMSG(OAL_KITL&&OAL_FUNC, (
        L"-OALKitlDeviceName(name = 0x%08x('%s')\r\n", pName, pName
    ));
    return pName;
}


//------------------------------------------------------------------------------
//
//  Function:  OALKitlDeviceType
//
OAL_KITL_TYPE OALKitlDeviceType(
        DEVICE_LOCATION *pDevLoc, OAL_KITL_DEVICE *pDevice
) {
    BOOL rc = FALSE;
    OAL_KITL_TYPE type = OAL_KITL_TYPE_NONE;
    
    OALMSG(OAL_KITL&&OAL_FUNC, (
        L"+OALKitlDeviceType(%d/%d/%08x, 0x%08x)\r\n",
        pDevLoc->IfcType, pDevLoc->BusNumber, pDevLoc->LogicalLoc, pDevice
    ));

    // Look for driver in list
    while (pDevice->name != NULL && !rc) {

        // Is it our device? Then move
        if (pDevLoc->IfcType != pDevice->ifcType) {
            // Move to next driver
            pDevice++;
            continue;
        }            

        // Identify device and read its address/interrupt depends on bus type
        switch (pDevLoc->IfcType) {
        case Internal:
            if (pDevLoc->LogicalLoc != pDevice->id) break;
            type = pDevice->type;
            rc = TRUE;
            break;
#ifdef KITL_PCI            
        case PCIBus:
            {
                UINT32 id;
                id = OALPCIGetId(
                    pDevLoc->BusNumber, *(OAL_PCI_LOCATION*)&pDevLoc->LogicalLoc
                );
                if (id != pDevice->id) break;
                type = pDevice->type;
                rc = TRUE;
            }                
            break;
#endif
        }

        // If we don't identify device skip it
        if (!rc) {
            pDevice++;
            continue;
        }
            
        // We get all we need
        break;
    }


    OALMSG(OAL_KITL&&OAL_FUNC, (L"-OALKitlDeviceType(type = %d)\r\n", type));
    return type;
}

//------------------------------------------------------------------------------
